package cn.tjnext.apply.web.controller;

import cn.tjnext.apply.contants.BaseModelAttributeNames;
import cn.tjnext.apply.contants.BasePagePaths;
import cn.tjnext.apply.contants.BaseRequestMappingPaths;
import cn.tjnext.apply.contants.CommonConstants;
import cn.tjnext.apply.dao.AbstractEntityDao;
import cn.tjnext.apply.entity.AbstractEntity;
import cn.tjnext.apply.repositories.AbstractRepository;
import cn.tjnext.apply.service.AbstractService;
import cn.tjnext.apply.web.model.BaseModel;
import cn.tjnext.apply.web.model.GenericEntityModel;
import cn.tjnext.apply.web.model.PageModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Optional;

public abstract class AbstractController<T extends AbstractEntity, R extends AbstractRepository<T>, D extends AbstractEntityDao<T, R>> {

    protected static final Logger log = LoggerFactory.getLogger(AbstractController.class);

    protected abstract T getNewEntity();
    protected abstract GenericEntityModel<T> createEntityModel(T entity);

    protected int getPageSize() {
        return CommonConstants.DEFAULT_PAGE_SIZE;
    }

    protected GenericEntityModel<T> getEditModel(Long id) {
        T entity = getNewEntity();
        if (id != null) {
            entity = getService().findOne(id);
        }

        return createEntityModel(entity);
    }

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        dateFormat.setLenient(false);
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
    }

    /**
     * 进入首页
     * @return
     */
    @RequestMapping(value = BaseRequestMappingPaths.INDEX, method = RequestMethod.GET)
    protected String toIndex() {
        return getBasePath() + BasePagePaths.INDEX;
    }

    /**
     * 进入列表页面（搜索 + 分页）
     * @param pageModel
     * @param model
     * @return
     */
    @RequestMapping(value =  BaseRequestMappingPaths.LIST, method = RequestMethod.GET)
    protected String toList(PageModel pageModel, Model model) {
        model.addAttribute(BaseModelAttributeNames.DATA_LIST, getService()
                .findAllByPage(pageModel, getPageSize()));
        return getBasePath() + BasePagePaths.LIST;
    }

    @ResponseBody
    @RequestMapping(value = BaseRequestMappingPaths.DELETE + BaseRequestMappingPaths.ID, method = RequestMethod.POST)
    protected BaseModel delete(@PathVariable Long id) {
        try {
            getService().delete(id);
            return new BaseModel();
        } catch (Exception e) {
            return new BaseModel(e.getMessage());
        }
    }

    @RequestMapping(value = BaseRequestMappingPaths.VIEW + BaseRequestMappingPaths.ID, method = RequestMethod.GET)
    protected String view(@PathVariable Long id, Model model) {
        model.addAttribute(BaseModelAttributeNames.ENTITY, getService().findOne(id));
        return getBasePath() + BasePagePaths.VIEW;
    }

    /**
     * 进入新增或修改页面
     * @param id
     * @param model
     * @return
     */
    @RequestMapping(value = {BaseRequestMappingPaths.EDIT + BaseRequestMappingPaths.ID, BaseRequestMappingPaths.EDIT},
            method = RequestMethod.GET)
    protected String toEdit(@PathVariable Optional<Long> id, Model model) {
        if (id.isPresent()) {
            model.addAttribute(BaseModelAttributeNames.DATA, getEditModel(id.get()));
        } else {
            model.addAttribute(BaseModelAttributeNames.DATA, getEditModel(null));
        }
        return getBasePath() + BasePagePaths.SAVE;
    }

    protected BaseModel saveImpl(T entity) {
        try {
            getService().createOrSave(entity);
            return new BaseModel();
        } catch (Exception e) {
            return new BaseModel(e.getMessage());
        }
    }

    /**
     * 设置返回路径
     * @return
     */
    protected abstract String getBasePath();

    /**
     * 设置调用Service
     * @return
     */
    protected abstract AbstractService<T, R, D> getService();
}